AWS CDKでAPI Gatewayのカスタムドメイン環境を構築してみた

AWS CDKでAPI Gatewayのカスタムドメイン環境を構築してみた

Clock Icon2019.11.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

おはようございます。CX事業本部の佐藤です。

AWS CDKでAPI Gatewayのカスタムドメイン環境を作ってみました。

環境

項目 バージョン
macOS Mojave 10.14.5
node v10.16.0
npm 6.9.0
AWS CDK 1.15.0 (build bdbe3aa)

CDKでカスタムドメイン環境を構築する

事前準備

カスタムドメイン環境を構築するには、事前にドメインの取得や証明書の取得が必要です。今回は無料で取得できるドメインで試しました。

ドメインの取得

freenomなどのドメインレジストラで、無料のドメインを取得しDNSの設定をします。弊社の以下のブログが参考になります。

https://dev.classmethod.jp/cloud/aws/mesoko-r53-cdn/

Certificate ManagerでSSL証明書を取得

弊社の以下のブログが参考になります。

https://dev.classmethod.jp/cloud/aws/certificate-manager-dns-validation-support/

パラメータストアにドメイン名と取得した証明書のARNを設定します。

後ほど、CDKから参照して使用するため、設定しておきます。

aws ssm put-parameter --type 'String' --name 'APIG_CUSTOM_DOMAIN_NAME' --value 'www.example.com'
aws ssm put-parameter --type 'String' --name 'APIG_CERTIFICATE_ARN' --value 'arn:aws:XXXX'

CDKでAPI Gatewayを作成する

AWS CDKを使ってインフラを構築していきます。以下、サンプルコードです。

テスト用Lambdaコード

export async function handler(event: any): Promise<any> {
  return 'test api gateway!';
}

CDKのコード

import * as cdk from '@aws-cdk/core';
import * as lambda from '@aws-cdk/aws-lambda';
import * as apig from '@aws-cdk/aws-apigateway';
import { NODE_LAMBDA_LAYER_DIR } from './process/setup';
import { Certificate } from '@aws-cdk/aws-certificatemanager';
import * as ssm from '@aws-cdk/aws-ssm';

export class ApigSampleStack extends cdk.Stack {

  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // パラメータストアからドメイン名と証明書のARNを取得
    const ApigCustomDomainName = ssm.StringParameter.fromStringParameterName(this, 'CustomDomainName', 'APIG_CUSTOM_DOMAIN_NAME');
    const ApigCertificateArn = ssm.StringParameter.fromStringParameterName(this, 'CertificateArn', 'APIG_CERTIFICATE_ARN');
		
    // Lambda Functionの作成
    const testFunction = new lambda.Function(this, 'TestFunction', {
      code: lambda.Code.fromAsset('src/lambda/handlers/api-gw'),
      functionName: 'testFunction',
      handler: 'test.handler',
      runtime: lambda.Runtime.NODEJS_10_X,
      memorySize: 256,
    });

    // API Gatewayの作成
    const api = new apig.RestApi(this, 'RestApi', {
      restApiName: 'test',
      // エンドポイントタイプの設定(SSL証明書を東京リージョンで作成したため、REGIONALで作成します。)
      endpointTypes: [
        apig.EndpointType.REGIONAL
      ],
      // CORSの設定
      defaultCorsPreflightOptions: {
        allowOrigins: apig.Cors.ALL_ORIGINS,
        allowMethods: ['POST', 'OPTIONS'],
        statusCode: 200,
      },
      description: "テスト用"
    });

    // カスタムドメインの設定
    const domainName = new apig.DomainName(this, 'CustomDomain', {
      // fromCertificateArnで証明書を取得します
      certificate: Certificate.fromCertificateArn(this, 'Certificate', ApigCertificateArn.stringValue),
      // パラメータストアに登録したドメイン名を設定します
      domainName: ApigCustomDomainName.stringValue,
      // REGINALタイプでカスタムドメインを設定します
      endpointType: apig.EndpointType.REGIONAL
    });
    // ベースパスマッピングの設定
    // https://www.example.com/v1/がベースパスとなります。
    domainName.addBasePathMapping(api, {
      basePath: 'v1'
    });

    // testリソース作成
    const testResource = api.root.addResource('test');
    
    // POSTメソッドの作成
    testResource.addMethod('POST', new apig.LambdaIntegration(testFunction, {
      connectionType: apig.ConnectionType.INTERNET,
      // 統合リクエストの設定
      requestTemplates: {
        'application/json': "$input.json('$')"
      },
      // 統合レスポンスの設定(CORS)
      integrationResponses: [
        {
          statusCode: '200',
          contentHandling: apig.ContentHandling.CONVERT_TO_TEXT,
          responseParameters: {
            'method.response.header.Access-Control-Allow-Headers': "'Origin,Content-Type,Authorization'",
            'method.response.header.Access-Control-Allow-Methods': "'POST,OPTIONS'",
            'method.response.header.Access-Control-Allow-Origin': "'*'"
          },
          responseTemplates: {
            'application/json': "$input.json('$')"
          }
        }
      ],
      passthroughBehavior: apig.PassthroughBehavior.WHEN_NO_MATCH,
      proxy: false,
    }),
      {
      	// メソッドレスポンスの設定(CORS)
        methodResponses: [
          {
            statusCode: '200',
            responseParameters: {
              'method.response.header.Access-Control-Allow-Headers': true,
              'method.response.header.Access-Control-Allow-Methods': true,
              'method.response.header.Access-Control-Allow-Origin': true
            }
          }
        ]
      }
    );
  }
}

デプロイ

AWSにデプロイします。

npm run build
cdk deploy

動作確認

デプロイできたら、動作確認をしてみます。PostmanでAPIを呼び出してみます。Lambdaが実行されて、 レスポンスが返ってきています。

まとめ

AWS CDKでカスタムドメイン環境を構築してみました。当初は、CDK + Swaggerの構成を考えていたんですが、CDKのAPI GatewayライブラリがまだSwaggerのインポートに対応していないため、SwaggerはAPI仕様書として別管理とし、現状はCDK単体で構築するのが良いかと思います。誰かの参考になれば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.